package org.geekbang.thinking.in.spring.dependency.lookup;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryUtils;
import org.springframework.beans.factory.HierarchicalBeanFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.beans.factory.xml.XmlBeanDefinitionReader;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.io.PrintStream;
import java.util.Map;

/**
 * 层次性依赖查找示例
 *
 * @author wangyh2
 * @version v1.0
 * @since 2021-09-17 16:30
 */
public class HierarchicalDependencyLookupDemo {
    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 HierarchicalDependencyLookupDemo 作为配置类（Configuration Class）
        applicationContext.register(HierarchicalDependencyLookupDemo.class);

        // 1. 获取 HierarchicalBeanFactory <- ConfigurableBeanFactory <- ConfigurableListableBeanFactory
        ConfigurableListableBeanFactory beanFactory = applicationContext.getBeanFactory();
        // 打印目前的父 beanFactory
        System.out.println("当前 BeanFactory 的 Parent BeanFactory ： " + beanFactory.getParentBeanFactory());

        // 2. 设置 Parent BeanFactory
        ConfigurableListableBeanFactory parentBeanFactory = createParentBeanFactory();
        beanFactory.setParentBeanFactory(parentBeanFactory);
        System.out.println("当前 BeanFactory 的 Parent BeanFactory ： " + beanFactory.getParentBeanFactory());

        // 3. 打印本地Bean
//        displayContainsLocalBean(beanFactory, "user");
//        displayContainsLocalBean(parentBeanFactory, "user");
//
//        // 4. 双亲委外查找Bean
//        displayContainsBean(beanFactory, "user");
//        displayContainsBean(parentBeanFactory, "user");

        // 5. BeanFactoryUtils#beanOfType  可以看到 仅获取的是当前beanFactory查找
//        ObjectFactoryCreatingFactoryBean user = BeanFactoryUtils.beanOfType(beanFactory, ObjectFactoryCreatingFactoryBean.class);
//        ObjectFactoryCreatingFactoryBean objectFactoryCreatingFactoryBean = BeanFactoryUtils.beanOfType(parentBeanFactory, ObjectFactoryCreatingFactoryBean.class);
//        System.out.println("当前Bean  BeanFactoryUtils#beanOfType" + user);
//        System.out.println("父Bean  BeanFactoryUtils#beanOfType" + objectFactoryCreatingFactoryBean);

        // 6. BeanFactoryUtils#beansOfTypeIncludingAncestors  可以看到 祖先的beanFactory查找 - 支持双亲委派
//        Map<String, ObjectFactoryCreatingFactoryBean> stringObjectFactoryCreatingFactoryBeanMap = BeanFactoryUtils.beansOfTypeIncludingAncestors(beanFactory, ObjectFactoryCreatingFactoryBean.class);
//        Map<String, ObjectFactoryCreatingFactoryBean> stringObjectFactoryCreatingFactoryBeanMap1 = BeanFactoryUtils.beansOfTypeIncludingAncestors(parentBeanFactory, ObjectFactoryCreatingFactoryBean.class);
//        System.out.println("当前Bean  BeanFactoryUtils#beanOfType" + stringObjectFactoryCreatingFactoryBeanMap);
//        System.out.println("父Bean  BeanFactoryUtils#beanOfType" + stringObjectFactoryCreatingFactoryBeanMap1);


        // 7. 根据 Java 注解查找名称列表 BeanFactoryUtils#beanNamesForTypeIncludingAncestors
    }

    private static boolean containsBean(HierarchicalBeanFactory beanFactory, String beanName) {
        BeanFactory parentBeanFactory = beanFactory.getParentBeanFactory();
        if (parentBeanFactory instanceof HierarchicalBeanFactory) {
            HierarchicalBeanFactory parentHierarchicalBeanFactory = HierarchicalBeanFactory.class.cast(parentBeanFactory);
            // 递归调用
            if (containsBean(parentHierarchicalBeanFactory, beanName)) {
                return true;
            }
        }
        return beanFactory.containsLocalBean(beanName);
    }

    private static void displayContainsBean(ConfigurableListableBeanFactory beanFactory, String beanName) {
        PrintStream printf = System.out.printf("当前 BeanFactory[%s] 是否包含 Bean[name : %s] : %s\n", beanFactory, beanName,
                containsBean(beanFactory, beanName));
    }

    private static void displayContainsLocalBean(HierarchicalBeanFactory beanFactory, String beanName) {
        System.out.printf("当前 BeanFactory[%s] 是否包含 Local Bean[name : %s] : %s\n", beanFactory, beanName,
                beanFactory.containsLocalBean(beanName));
    }

    private static ConfigurableListableBeanFactory createParentBeanFactory() {
        // 创建 BeanFactory 容器
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        // XML 配置文件 ClassPath 路径
        String location = "classpath:/META-INF/dependency-lookup-context.xml";
        // 加载配置
        reader.loadBeanDefinitions(location);
        return beanFactory;
    }
}
